package bussines;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import model.Movie;
import model.Subtitle;
import bussines.logger.Log;
import bussines.progress.ProgressManager;

public class SubtitlesMatcher {

	private static enum RenameStrategy {
		MOVIE_SUB, SUB_MOVIE
	};

	private static final RenameStrategy DEFAULT_RENAME_STRATEGY = RenameStrategy.MOVIE_SUB;
	private ProgressManager pm = ProgressManager.getInstance();

	/**
	 * 
	 * @param path
	 * @return
	 */
	private List<Movie> findMovies(String path) {

		FileFilter moviesFilter = new FileFilter() {
			public boolean accept(File pathname) {
				if (pathname.isFile() && !Arrays.asList(Subtitle.type).contains(FileUtils.getExtension(pathname)))
					return true;
				else
					return false;
			}

		};
		List<File> movies = FileUtils.listFiles(path, moviesFilter);
		List<Movie> result = new ArrayList<Movie>(movies.size());
		for (File file : movies) {
			result.add(new Movie(file));
			Log.debug(file.getName());
		}

		return result;
	}

	/**
	 * 
	 * @param path
	 * @return
	 */
	private List<Subtitle> findSubtitles(String path) {

		FileFilter subtitlesFilter = new FileFilter() {
			public boolean accept(File pathname) {
				if (pathname.isFile() && Arrays.asList(Subtitle.type).contains(FileUtils.getExtension(pathname)))
					return true;
				else
					return false;
			}

		};
		List<File> subtitles = FileUtils.listFiles(path, subtitlesFilter);
		List<Subtitle> result = new ArrayList<Subtitle>(subtitles.size());
		for (File file : subtitles) {
			result.add(new Subtitle(file));
			Log.debug(file.getName());
		}

		return result;

	}

	private MovSubMatch matchSubtitle(Movie movie, List<Subtitle> subtitles) {
		Log.debug("Analyzing movie:" + movie.getName());
		MovSubMatch result = null;
		double maxScore = -1;
		for (Subtitle subtitle : subtitles) {
			double score = 0;
			// Check series
			if (movie.getSeries() != null && movie.getSeries().equals(subtitle.getSeries())) {
				score += 4;
			}
			// Check episode
			if (movie.getEpisode() != null && movie.getEpisode().equals(subtitle.getEpisode())) {
				score += 4;
			}
			// Try to match names
			if (movie.getName().length() > subtitle.getName().length())
				score += StringMatching.compareStrings(movie.getName(), subtitle.getName());
			else {
				score += StringMatching.compareStrings(subtitle.getName(), movie.getName());
			}

			Log.debug("Score for " + subtitle.getName() + ':' + score);
			if (score > maxScore) {
				result = new MovSubMatch(movie, subtitle, score);
				maxScore = score;
			}

		}

		return result;

	}

	private void renameFiles(List<MovSubMatch> movSub, RenameStrategy rs) {

		for (MovSubMatch movSubMatch : movSub) {
			Movie movie = movSubMatch.getMovie();
			Subtitle sub = movSubMatch.getSubtitle();
			Log.log("Match score:" + movSubMatch.getScore() + "\t" + movie.getFile().getName() + "<->"
			        + sub.getFile().getName());
			switch (rs) {
			case MOVIE_SUB:
				FileUtils.renameKeepExtension(movie.getFile(), sub.getFile());
				break;
			case SUB_MOVIE:
				FileUtils.renameKeepExtension(sub.getFile(), movie.getFile());
				break;
			}

		}
	}

	public void match(String path) {
		Log.log("Starting work for:" + path);
		List<MovSubMatch> matches = new ArrayList<MovSubMatch>();
		List<Movie> movies = findMovies(path);
		List<Subtitle> subtitles = findSubtitles(path);
		pm.notifyProgressListenersOnStart(movies.size() + 1);
		for (Movie movie : movies) {
			MovSubMatch match = matchSubtitle(movie, subtitles);
			if (match != null) {
				matches.add(match);
			}
			pm.notifyProgressListenersOnProgress(1);
		}
		Collections.sort(matches);
		Collections.reverse(matches);
		renameFiles(matches, DEFAULT_RENAME_STRATEGY);
		pm.notifyProgressListenersOnProgress(1);
		Log.log("Done.");

	}

}
